package service

import (
	"fmt"
	"golang.org/x/crypto/bcrypt"
	"ruoyi-go/internal/core/auth"
	"ruoyi-go/internal/core/constants"
	commService "ruoyi-go/internal/web/common/service"
	"ruoyi-go/internal/web/system/domain"
	"ruoyi-go/internal/web/system/domain/vo"
	"ruoyi-go/internal/web/system/service/userstatus"
)

// Login 登录
func Login(username, password string, captcha, uuid string) (string, error) {
	// 校验验证码
	if err := commService.ValidateCaptcha(uuid, captcha); err != nil {
		return "", err
	}
	// 前置验证，账号/密码合法性的验证
	if err := loginPreCheck(username, password); err != nil {
		return "", err
	}
	// 账号密码进行登录
	loginUser, err := loadUserByUsername(username, password)
	if err != nil {
		return "", err
	}
	// 生成token
	token, e1 := auth.GenerateTokenForLoginUser(&loginUser)
	if e1 != nil {
		return "", e1
	}
	return token, nil
}

// 登录前置检查，账号/密码合法性的验证
func loginPreCheck(username, password string) error {
	// 用户名或密码为空 错误
	if username == "" || password == "" {
		//TODO 记录登录日志
		return fmt.Errorf("user.not.exists") // 账号不存在的错误
	}
	// 密码如果不在指定范围内 错误
	if len(password) < constants.PASSWORD_MIN_LENGTH || len(password) > constants.PASSWORD_MAX_LENGTH {
		return fmt.Errorf("user.password.not.match")
	}
	// 用户名不在指定范围内 错误
	if len(password) < constants.USERNAME_MIN_LENGTH || len(password) > constants.USERNAME_MAX_LENGTH {
		return fmt.Errorf("user.password.not.match")
	}
	// IP黑名单校验，暂无

	return nil
}

// 使用账号密码登录
func loadUserByUsername(username, password string) (vo.LoginUser, error) {
	// 查询出用户
	one := domain.SysUserModel().GetOne(domain.SysUser{UserName: username})
	if one == nil { // 用户不存在
		return vo.LoginUser{}, fmt.Errorf("user.not.exists")
	}
	if userstatus.DELETED.Code == one.Status { // 用户已删除
		return vo.LoginUser{}, fmt.Errorf("user.password.delete")
	}
	if userstatus.DISABLE.Code == one.Status { // 用户已停用
		return vo.LoginUser{}, fmt.Errorf("user.blocked")
	}
	// 验证密码
	if err := bcrypt.CompareHashAndPassword([]byte(one.Password), []byte(password)); err != nil {
		return vo.LoginUser{}, fmt.Errorf("user.password.not.match")
	}
	// 把密码屏蔽
	one.Password = "******"

	return vo.LoginUser{
		UserID:      one.UserID,
		DeptID:      one.DeptID,
		Permissions: []string{},
		User:        one,
	}, nil
}
